﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using P;

using IMLibrary;
using IMLibrary.BinaryPacket;
using IMLibrary.Security;
using IMLibrary.WS; 

using Ourmsg.Enum;
using Ourmsg.Factory;
using Ourmsg;

namespace Ourmsg.APPClient
{
    public class MsgClient
    {
        #region 构造函数
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="serverIP">服务器IP或域名</param>
        /// <param name="serverPort"></param>
        public MsgClient(string serverIP, int serverPort = 2014)
        {
            ServerIP = serverIP;
            ServerPort = serverPort;
            this.Encrypt = true;
            this.Compress = true; 

            //Task.Factory.StartNew(() => startRecived(), TaskCreationOptions.LongRunning);
        }

        private void startRecived()
        {
            while (true)
            {
                if (ReciveDatas.Count > 0)
                    PacketReceived(ReciveDatas.Dequeue());
            }
        }

        #endregion

        #region 属性  

        /// <summary>
        /// 服务器IP
        /// </summary>
        public string ServerIP
        { set; get; }
        /// <summary>
        /// 服务器端口
        /// </summary>
        public int ServerPort
        { set; get; }
        /// <summary>
        /// 设置或获取掉线后是否自动重连服务器
        /// </summary>
        public bool AutoConnection
        { set; get; }
        /// <summary>
        /// 是否压缩
        /// </summary>
        public bool Compress
        { set; get; }
        /// <summary>
        /// 是否加密
        /// </summary>
        public bool Encrypt
        { set; get; }
        /// <summary>
        /// 是否APP客户端
        /// </summary>
        public bool APPClient
        { set; get; }


        /// <summary>
        /// 登录帐号信息
        /// </summary>
        public Auth MyAuth = new Auth();
        /// <summary>
        ///  加密密钥
        /// </summary>
        private byte[] PasswordKey = new byte[16];
        ///// <summary>
        ///// 密码
        ///// </summary>
        //private string Password = ""; 
        /// <summary>
        /// 标识当前是否正在登录
        /// </summary>
        bool Logining = false;
        /// <summary>
        /// 在线状态字节数组
        /// </summary>
        byte[] ShowTypeData = new byte[1];
        /// <summary>
        /// 是否连接
        /// </summary>
        public bool IsConnection = false;
        /// <summary>
        /// 客户端套接字
        /// </summary>
        WebSocket wsClient;
        /// <summary>
        /// 消息队列
        /// </summary>
        Queue<byte[]> ReciveDatas = new Queue<byte[]>();
        #endregion

        #region 事件
        public delegate void EventHandler(object sender, MsgClientEventArgs e);
        /// <summary>
        /// 与服务器联接超时事件
        /// </summary>
        public event EventHandler ConnectOutTime;
        private void onConnectOutTime()
        {
            if (ConnectOutTime != null)
                ConnectOutTime(this, null);

        }
        /// <summary>
        /// 已与服务器建立联接事件
        /// </summary>
        public event EventHandler Connected;
        private void onConnected()
        {
            if (Connected != null)
                Connected(this, null);
        }

        /// <summary>
        /// 已与服务器断开联接事件
        /// </summary>
        public event EventHandler Disconnected;
        private void onDisconnected()
        {
            if (Disconnected != null)
                Disconnected(this, null);

        }

        /// <summary>
        /// 注册用户成功事件
        /// </summary>
        public event EventHandler RecivedUserRegister;
        private void onRecivedUserRegister(MsgClientEventArgs e)
        {
            if (RecivedUserRegister != null)
                RecivedUserRegister(this, e);
        }

        /// <summary>
        /// 登录成功事件
        /// </summary>
        public event EventHandler Logined;
        private void onLogined(MsgClientEventArgs e)
        {
            if (Logined != null)
                Logined(this, e);
        }

        /// <summary>
        /// 登录失败事件
        /// </summary>
        public event EventHandler LoginFailed;
        private void onLoginFailed()
        {
            if (LoginFailed != null)
                LoginFailed(this, null);
        }

        /// <summary>
        /// 别处登录事件
        /// </summary>
        public event EventHandler LoginElse;
        private void onLoginElse()
        {
            if (LoginElse != null)
                LoginElse(this, null);
        }

        /// <summary>
        /// 收到分组列表数据list<group>事件
        /// </summary>
        public event EventHandler RecivedGroups;
        private void onRecivedGroups(MsgClientEventArgs e)
        {
            if (RecivedGroups != null)
                RecivedGroups(this, e);
        }

        /// <summary>
        /// 收到好友基本列表数据list<UserFriendBaseInfo>事件
        /// </summary>
        public event EventHandler RecivedFriendBaseInfos;
        private void onRecivedFriendBaseInfos(MsgClientEventArgs e)
        {
            if (RecivedFriendBaseInfos != null)
                RecivedFriendBaseInfos(this, e);
        }

        /// <summary>
        /// 收到群基本信息列表数据list<UserRoomBaseInfo>事件
        /// </summary>
        public event EventHandler RecivedRoomBaseInfos;
        private void onRecivedRoomBaseInfos(MsgClientEventArgs e)
        {
            if (RecivedRoomBaseInfos != null)
                RecivedRoomBaseInfos(this, e);
        }

        /// <summary>
        /// 收到群分组信息列表数据list<UserRoomGroup>事件
        /// </summary>
        public event EventHandler RecivedRoomGroups;
        private void onRecivedRoomGroups(MsgClientEventArgs e)
        {
            if (RecivedRoomGroups != null)
                RecivedRoomGroups(this, e);
        }

        /// <summary>
        /// 收到黑名单信息列表数据list<UserRoomGroup>事件
        /// </summary>
        public event EventHandler RecivedBlacklists;
        private void onRecivedBlacklists(MsgClientEventArgs e)
        {
            if (RecivedBlacklists != null)
                RecivedBlacklists(this, e);
        }

        /// <summary>
        /// 收到多位好友在线状态列表list<Presence>事件
        /// </summary>
        public event EventHandler RecivedFriendPresences;
        private void onRecivedFriendPresences(MsgClientEventArgs e)
        {
            if (RecivedFriendPresences != null)
                RecivedFriendPresences(this, e);
        }

        /// <summary>
        /// 收到群中多位好友在线状态列表list<Presence>事件
        /// </summary>
        public event EventHandler RecivedRoomFriendPresences;
        private void onRecivedRoomFriendPresences(MsgClientEventArgs e)
        {
            if (RecivedRoomFriendPresences != null)
                RecivedRoomFriendPresences(this, e);
        }

        /// <summary>
        /// 收到用户消息事件
        /// </summary>
        public event EventHandler RecivedUserMsg;
        private void onRecivedUserMsg(MsgClientEventArgs e)
        {
            if (RecivedUserMsg != null)
                RecivedUserMsg(this, e);
        }

        /// <summary>
        /// 收到用户消息事件
        /// </summary>
        public event EventHandler RecivedRoomMsg;
        private void onRecivedRoomMsg(MsgClientEventArgs e)
        {
            if (RecivedRoomMsg != null)
                RecivedRoomMsg(this, e);
        }

        /// <summary>
        /// 收到未知消息事件
        /// </summary>
        public event EventHandler RecivedElseData;
        private void onRecivedElseData(MsgClientEventArgs e)
        {
            if (RecivedElseData != null)
                RecivedElseData(this, e);
        }
        /// <summary>
        /// 收到系统消息（警告、调试、错误等）事件
        /// </summary>
        public event EventHandler RecivedSystemMsg;
        private void onRecivedSystemMsg(MsgClientEventArgs e)
        {
            if (RecivedSystemMsg != null)
                RecivedSystemMsg(this, e);
        }

        /// <summary>
        /// 收到创建群消息事件
        /// </summary>
        public event EventHandler RecivedCreateRoom;
        private void onRecivedCreateRoom(MsgClientEventArgs e)
        {
            if (RecivedCreateRoom != null)
                RecivedCreateRoom(this, e);
        }


        /// <summary>
        /// 收到群资料
        /// </summary>
        public event EventHandler RecivedRoomData;
        private void onRecivedRoomData(MsgClientEventArgs e)
        {
            if (RecivedRoomData != null)
                RecivedRoomData(this, e);
        }

        /// <summary>
        /// 收到成功设置群管理员消息 SetRoomUserCard
        /// </summary>
        public event EventHandler RecivedSetRoomManger;
        private void onRecivedSetRoomManger(MsgClientEventArgs e)
        {
            if (RecivedSetRoomManger != null)
                RecivedSetRoomManger(this, e);
        }

        /// <summary>
        /// 收到成功设置群用户名片消息  
        /// </summary>
        public event EventHandler RecivedSetRoomUserCard;
        private void onRecivedSetRoomUserCard(MsgClientEventArgs e)
        {
            if (RecivedSetRoomUserCard != null)
                RecivedSetRoomUserCard(this, e);
        }


        /// <summary>
        /// 收到成功设置群基本信息消息  
        /// </summary>
        public event EventHandler RecivedSetRoomBaseInfo;
        private void onRecivedSetRoomBaseInfo(MsgClientEventArgs e)
        {
            if (RecivedSetRoomBaseInfo != null)
                RecivedSetRoomBaseInfo(this, e);
        }

        /// <summary>
        /// 收到成功删除群用户消息
        /// </summary>
        public event EventHandler RecivedDelRoomUser;
        private void onRecivedDelRoomUser(MsgClientEventArgs e)
        {
            if (RecivedDelRoomUser != null)
                RecivedDelRoomUser(this, e);
        }

        /// <summary>
        /// 收到删除群消息
        /// </summary>
        public event EventHandler RecivedDelRoom;
        private void onRecivedDelRoom(MsgClientEventArgs e)
        {
            if (RecivedDelRoom != null)
                RecivedDelRoom(this, e);
        }


        /// <summary>
        /// 收到请求添加好友回应消息事件
        /// </summary>
        public event EventHandler RecivedResponsesAddRoom;
        private void onRecivedResponsesAddRoom(MsgClientEventArgs e)
        {
            if (RecivedResponsesAddRoom != null)
                RecivedResponsesAddRoom(this, e);
        }

        /// <summary>
        /// 收到请求添加好友回应消息事件
        /// </summary>
        public event EventHandler RecivedResponsesAddFriend;
        private void onRecivedResponsesAddFriend(MsgClientEventArgs e)
        {
            if (RecivedResponsesAddFriend != null)
                RecivedResponsesAddFriend(this, e);
        }

        /// <summary>
        /// 收到邀请加群回应消息事件
        /// </summary>
        public event EventHandler RecivedResponsesInviteAddRoom;
        private void onRecivedResponsesInviteAddRoom(MsgClientEventArgs e)
        {
            if (RecivedResponsesInviteAddRoom != null)
                RecivedResponsesInviteAddRoom(this, e);
        }

        /// <summary>
        /// 收到请求加群消息事件
        /// </summary>
        public event EventHandler RecivedRequestAddRoom;
        private void onRecivedRequestAddRoom(MsgClientEventArgs e)
        {
            if (RecivedRequestAddRoom != null)
                RecivedRequestAddRoom(this, e);
        }

        /// <summary>
        /// 收到删除好友消息
        /// </summary>
        public event EventHandler RecivedQuitRoom;
        private void onRecivedQuitRoom(MsgClientEventArgs e)
        {
            if (RecivedQuitRoom != null)
                RecivedQuitRoom(this, e);
        }

        /// <summary>
        /// 收到邀请加群消息事件
        /// </summary>
        public event EventHandler RecivedInviteAddRoom;
        private void onRecivedInviteAddRoom(MsgClientEventArgs e)
        {
            if (RecivedInviteAddRoom != null)
                RecivedInviteAddRoom(this, e);
        }

        /// <summary>
        /// 收到请求加好友消息事件
        /// </summary>
        public event EventHandler RecivedRequestAddFriend;
        private void onRecivedRequestAddFriend(MsgClientEventArgs e)
        {
            if (RecivedRequestAddFriend != null)
                RecivedRequestAddFriend(this, e);
        }

        /// <summary>
        /// 收到删除好友消息事件
        /// </summary>
        public event EventHandler RecivedDelFriend;
        private void onRecivedDelFriend(MsgClientEventArgs e)
        {
            if (RecivedDelFriend != null)
                RecivedDelFriend(this, e);
        }

        /// <summary>
        /// 收到查询用户结果消息事件
        /// </summary>
        public event EventHandler RecivedQueryUsers;
        private void onRecivedQueryUsers(MsgClientEventArgs e)
        {
            if (RecivedQueryUsers != null)
                RecivedQueryUsers(this, e);
        }

        /// <summary>
        /// 收到查询群结果消息事件
        /// </summary>
        public event EventHandler RecivedQueryRooms;
        private void onRecivedQueryRooms(MsgClientEventArgs e)
        {
            if (RecivedQueryRooms != null)
                RecivedQueryRooms(this, e);
        }


        #endregion

        #region 包到达事件处理过程
        //private delegate void PacketReceivedDelegate(byte[] Data);
        private void PacketReceived(byte[] Data)
        {
            if (Data.Length < BinaryMsg.HeaderLength) return;
            var msg = new BinaryMsg(Data);

            #region 服务器其他回复

            #region 解密解压
            var len = msg.PayloadLength;
            if (msg.Encrypt)//先解密
                msg.Payload = Encryption.Decrypt3DES(msg.Payload, PasswordKey);
            Console.WriteLine(string.Format("解密前{0}:解密后{1}", len, msg.PayloadLength));

            if (msg.Compress)//再解压
                msg.Payload =IMLibrary.GZip.Stream.Decompress(msg.Payload);
            Console.WriteLine(string.Format("解压前{0}:解压后{1}", len, msg.PayloadLength));
            #endregion

            string Payload = msg.GetPayloadString();
            switch (msg.CommandType)
            {
                case (byte)CommandType.Auth:
                    {
                        var auth = XML.ConvertToObject(Payload) as Auth;
                        if (auth != null)
                        {
                            MyAuth = auth;
                            onLogined(new MsgClientEventArgs(auth));
                            Console.WriteLine("登录成功！" + Payload);
                        }
                    }
                    break;
                case (byte)CommandType.AuthError://登录失败 
                    {
                        Console.WriteLine("登录失败！");
                        onLoginFailed();
                    }
                    break;
                case (byte)CommandType.ElseLogin:
                    {
                        Console.WriteLine("用户别处登录！");
                        onLoginElse();
                    }
                    break;
                case (byte)CommandType.GroupData://收到分组数据
                    {
                        Console.WriteLine("收到分组数据！" + Payload);
                        onRecivedGroups(new MsgClientEventArgs(XML.ConvertToObjects(Payload)));
                    }
                    break;
                case (byte)CommandType.FriendBaseData://收到好友基本信息数据
                    {
                        Console.WriteLine("收到好友基本数据！" + Payload);
                        onRecivedFriendBaseInfos(new MsgClientEventArgs(XML.ConvertToObjects(Payload)));
                    }
                    break;
                case (byte)CommandType.RoomGroups://收到群分组信息数据
                    {
                        Console.WriteLine("收到群分组信息数据！" + Payload);
                        onRecivedRoomGroups(new MsgClientEventArgs(XML.ConvertToObjects(Payload)));
                    }
                    break;
                case (byte)CommandType.RoomBaseData://收到群基本信息数据
                    {
                        Console.WriteLine("收到群基本数据！" + Payload);
                        onRecivedRoomBaseInfos(new MsgClientEventArgs(XML.ConvertToObjects(Payload)));
                    }
                    break;
                case (byte)CommandType.Blacklists://收到黑名单信息数据
                    {
                        Console.WriteLine("收到黑名单信息数据！" + Payload);
                        onRecivedBlacklists(new MsgClientEventArgs(XML.ConvertToObjects(Payload)));
                    }
                    break;
                case (byte)CommandType.FriendPresences://收到多位好友在线状态列表
                    {
                        Console.WriteLine("收到多位好友在线状态列表！" + Payload);
                        onRecivedFriendPresences(new MsgClientEventArgs(XML.ConvertToObjects(Payload)));
                    }
                    break;
                case (byte)CommandType.RoomFriendPresences://收到群中多位好友在线状态列表
                    {
                        Console.WriteLine("收到群中多位好友在线状态列表！" + Payload);
                        onRecivedRoomFriendPresences(new MsgClientEventArgs(XML.ConvertToObjects(Payload)));
                    }
                    break;
                case (byte)CommandType.UserMessage://收到用户消息
                    {
                        Console.WriteLine("收到用户消息！" + Payload);
                        onRecivedUserMsg(new MsgClientEventArgs(XML.ConvertToObject(Payload), msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.RoomMessage://收到群消息
                    {
                        Console.WriteLine("收到群消息！" + Payload);
                        onRecivedRoomMsg(new MsgClientEventArgs(XML.ConvertToObject(Payload), msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.CreateRoom://创建群返回结果
                    {
                        Console.WriteLine("创建群返回结果！" + 0);
                        RoomBaseInfo rbinfo = XML.ConvertToObject(Payload) as RoomBaseInfo;
                        if (rbinfo != null)
                        {
                            onRecivedCreateRoom(new MsgClientEventArgs(null, msg.To, msg.From));
                            onRecivedRoomBaseInfos(new MsgClientEventArgs(XML.ConvertToObjects(Payload)));
                        }
                    }
                    break;
                case (byte)CommandType.GetRoomUserData://获得群用户资料
                    {
                        Console.WriteLine("获得群详细资料！" + Payload);
                        onRecivedRoomData(new MsgClientEventArgs(XML.ConvertToObjects(Payload), msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.SetRoomManger://设置群管理员
                    {
                        Console.WriteLine("收到成功设置群管理员消息！" + Payload);
                        onRecivedSetRoomManger(new MsgClientEventArgs(XML.ConvertToObject(Payload), msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.SetRoomUserCard://设置群用户名片
                    {
                        Console.WriteLine("收到成功设置群用户名片消息！" + Payload);
                        onRecivedSetRoomUserCard(new MsgClientEventArgs(XML.ConvertToObject(Payload), msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.SetRoomBaseInfo://设置群基本信息
                    {
                        Console.WriteLine("收到成功设置群基本信息消息！" + Payload);
                        onRecivedSetRoomBaseInfo(new MsgClientEventArgs(XML.ConvertToObject(Payload), msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.DelRoomUser://删除群用户
                    {
                        Console.WriteLine("收到成功删除群用户消息！" + Payload);

                        var rUser = XML.ConvertToObject(Payload) as RoomUser;
                        if (rUser == null) return;
                        if (rUser.UserID == MyAuth.UserID)
                            onRecivedQuitRoom(new MsgClientEventArgs(rUser, msg.To, msg.From));//触发退出群事件
                        else
                            onRecivedDelRoomUser(new MsgClientEventArgs(rUser, msg.To, msg.From));//触发删除群用户事件
                    }
                    break;
                case (byte)CommandType.InviteAddRoom://收到邀请加群消息
                    {
                        Console.WriteLine("收到邀请加群消息！" + Payload);
                        var invMsg = XML.ConvertToObject(Payload) as InviteMsg;
                        if (invMsg != null)
                            onRecivedInviteAddRoom(new MsgClientEventArgs(invMsg, msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.RequestAddFriend://收到请求加好友消息
                    {
                        Console.WriteLine("收到请求加好友消息！" + Payload);
                        var invMsg = XML.ConvertToObject(Payload) as InviteMsg;
                        if (msg != null)
                            onRecivedRequestAddFriend(new MsgClientEventArgs(invMsg, msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.RequestAddRoom://收到请求加群消息
                    {
                        Console.WriteLine("收到请求加群消息！" + Payload);
                        var invMsg = XML.ConvertToObject(Payload) as InviteMsg;
                        if (invMsg != null)
                            onRecivedRequestAddRoom(new MsgClientEventArgs(invMsg, msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.ResponsesInviteAddRoom://收到邀请加群回应消息
                    {
                        Console.WriteLine("收到邀请加群回应消息！" + Payload);
                        var invMsg = XML.ConvertToObject(Payload) as InviteMsg;
                        if (invMsg != null)
                            onRecivedResponsesInviteAddRoom(new MsgClientEventArgs(invMsg, msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.ResponsesAddRoom://收到请求加群回应消息
                    {
                        Console.WriteLine("收到请求加群回应消息！" + Payload);
                        var invMsg = XML.ConvertToObject(Payload) as InviteMsg;
                        if (invMsg != null)
                            onRecivedResponsesAddRoom(new MsgClientEventArgs(invMsg, msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.ResponsesAddFriend://收到请求加好友回应消息
                    {
                        Console.WriteLine("收到请求加好友回应消息！" + Payload);
                        var invMsg = XML.ConvertToObject(Payload) as InviteMsg;
                        if (invMsg != null)
                            onRecivedResponsesAddFriend(new MsgClientEventArgs(invMsg, msg.To, msg.From));
                    }
                    break;
                case (byte)CommandType.DelFriend://删除好友
                    {
                        onRecivedDelFriend(new MsgClientEventArgs(null, msg.To, msg.From));
                        Console.WriteLine("收到 删除好友 消息！" + Payload);
                    }
                    break;
                case (byte)CommandType.DelRoom://删除群
                    {
                        onRecivedDelRoom(new MsgClientEventArgs(null, msg.To, msg.From));
                        Console.WriteLine("收到 删除群 消息！" + Payload);
                    }
                    break;
                case (byte)CommandType.QuitRoom://退出群
                    {
                        var user = XML.ConvertToObject(Payload) as RoomUser;
                        if (user != null)
                            onRecivedQuitRoom(new MsgClientEventArgs(user, msg.To, msg.From));
                        Console.WriteLine("收到 退出群 消息！" + Payload);
                    }
                    break;

                #region 处理查询结果
                case (byte)CommandType.Query://收到查询消息
                    {
                        var objs = XML.ConvertToObjects(Payload);
                        if (objs == null) return;
                        List<QueryUser> qus = null;
                        List<QueryRoom> qrs = null;
                        foreach (object obj in objs)
                        {
                            if (obj is QueryUser)
                            {
                                if (qus == null) qus = new List<QueryUser>();
                                if (qus != null)
                                    qus.Add(obj as QueryUser);
                            }
                            else if (obj is QueryRoom)
                            {
                                if (qrs == null) qrs = new List<QueryRoom>();
                                if (qrs != null)
                                    qrs.Add(obj as QueryRoom);
                            }
                        }

                        if (qus != null && qus.Count > 0)
                        {
                            onRecivedQueryUsers(new MsgClientEventArgs(qus));
                            Console.WriteLine("收到查询用户结果消息！" + Payload);
                        }
                        if (qrs != null && qrs.Count > 0)
                        {
                            onRecivedQueryRooms(new MsgClientEventArgs(qrs));
                            Console.WriteLine("收到查询群结果消息！" + Payload);
                        }
                    }
                    break;
                #endregion

                case (byte)CommandType.UserGroupInfoOperation://返回分组操作信息
                    {

                        Console.WriteLine("返回分组操作信息！" + Payload);
                    }
                    break;
                case (byte)CommandType.RoomGroupInfoOperation://返回群分组操作信息
                    {

                        Console.WriteLine("返回群分组操作信息！" + Payload);
                    }
                    break;
            }
            #endregion
        }
        #endregion

        #region 登录服务器函数
        /// <summary>
        /// 登录服务器
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="password"></param>
        /// <param name="showType"></param>
        public void ReadyLogin(string userID, string password, ShowType showType)
        {
            if (Logining)
                return;//如果正在登录或已经登录则退出登录。 
            Logining = true;//标识正在登录，防止重复调用登录函数

            MyAuth.AuthID = userID;
            MyAuth.Password = Hasher.GetMD5String(password);
            MyAuth.ShowType = showType;

            this.PasswordKey = Hasher.GetMD5Bytes(MyAuth.Password);//密钥 
            if (wsClient == null)
            {
                wsClient = new WebSocket(string.Format("ws://{0}:{1}/Chats", ServerIP, ServerPort));
                wsClient.SetCredentials("Ourmsg", "123456@Ourmsg.net", true);
                wsClient.OnClose += WsClient_OnClose;
                wsClient.OnOpen += WsClient_OnOpen;
                wsClient.OnMessage += WsClient_OnMessage;
            }
            wsClient.ConnectAsync();
        }

        private void WsClient_OnMessage(object sender, MessageEventArgs e)
        {
            if (e.RawData.Length < BinaryMsg.HeaderLength) return;

            //this.ReciveDatas.Enqueue(e.RawData);//将消息压入栈

            //PacketReceivedDelegate md = new PacketReceivedDelegate(PacketReceived);
            //md(e.RawData);
            PacketReceived(e.RawData);
        }

        private void WsClient_OnOpen(object sender, EventArgs e)
        {
            Console.WriteLine("conneced!");
            IsConnection = true;
            onConnected();
            Login(MyAuth.AuthID, MyAuth.Password, MyAuth.ShowType);
        }

        private void WsClient_OnClose(object sender, EventArgs e)
        {
            Logining = false;
            IsConnection = false; 
            wsClient = null;
            onDisconnected();
            Console.WriteLine("conn close !");
        }
        #endregion

        #region 向服务器发送登录认证消息
        /// <summary>
        /// 登录认证
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="password"></param>
        /// <param name="showType"></param>
        void Login(string userID, string password, ShowType showType)
        {
            var auth = new Auth();
            auth.AuthID = userID;
            auth.Password = password;
            auth.ShowType = showType;
            auth.Encrypt = this.Encrypt;
            auth.Compress = this.Compress;
            sendMsg(CommandType.Auth, auth);
        }
        #endregion

        #region 更改自己的在线状态
        /// <summary>
        /// 更改自己的在线状态
        /// </summary>
        /// <param name="showType"></param>
        public void SetChangeShowType(ShowType showType)
        {
            // if (showType != MyAuth.ShowType && showType != ShowType.Offline)
            {
                Presence presence = new Presence();
                presence.UserID = MyAuth.UserID;
                presence.ShowType = showType;
                sendMsg(CommandType.Presence, presence);
            }
        }
        #endregion

        #region 注册新用户
        /// <summary>
        /// 注册新用户
        /// </summary>
        /// <param name="userRegister"></param>
        public void UserRegister(UserRegister userRegister,string serverIP,int port)
        {
            if (userRegister.UserName == null || userRegister.UserName == string.Empty) return;
            if (userRegister.Password == null || userRegister.Password.Length < 6) return;
            userRegister.Password =  Hasher.GetMD5String(userRegister.Password);
            WebSocket webSocket = new WebSocket(string.Format("ws://{0}:{1}/RegisterUser", serverIP, port));
            webSocket.SetCredentials("liggyi", "liggyi@Ourmsg.net", true);
            webSocket.OnOpen += (s, e) =>
            {
                var msg = new BinaryMsg();
                msg.CommandType = (byte)CommandType.UserRegister;
                msg.Compress = false;
                msg.Encrypt = false;
                msg.Payload = XML.ConvertToArray(userRegister);
                msg.Payload = Encryption.Encrypt3DES(msg.Payload);
                msg.Encrypt = true;
                webSocket.SendAsync(msg.ToArray(), null);
            };
            webSocket.OnClose += (s, e) =>
           {

           };
            webSocket.OnMessage += (s, e) =>
           {
               if (e.Data.Length < BinaryMsg.HeaderLength) return;
               var msg = new BinaryMsg(e.RawData);

               #region 注册用户成功
               if (msg.CommandType == (byte)CommandType.UserRegister)
               {
                   #region 解密解压
                   if (msg.Encrypt)//先解密
                       msg.Payload = Encryption.Decrypt3DES(msg.Payload);
                   if (msg.Compress)//再解压
                       msg.Payload = IMLibrary.GZip.Stream.Decompress(msg.Payload);
                   #endregion

                   onRecivedUserRegister(new MsgClientEventArgs(XML.ConvertToObject(msg.GetPayloadString())));
                   Console.WriteLine("收到注册用户成功！");
                   webSocket.Close();
               }
               #endregion
           };
            webSocket.ConnectAsync();
        }

        #endregion

        #region 群操作

        #region 创建群
        /// <summary>
        /// 创建群
        /// </summary>
        /// <param name="r"></param>
        public void CreateRoom(RoomBaseInfo r)
        {
            r.CreateUserID = MyAuth.UserID;
            sendMsg(CommandType.CreateRoom, r);
        }
        #endregion

        #region 获得群资料
        /// <summary>
        /// 获得群资料
        /// </summary>
        public void GetRoomData(UInt32 roomID)
        {
            sendMsg(CommandType.GetRoomUserData, null, roomID, true);
        }
        #endregion

        #region 更新群基本信息
        /// <summary>
        /// 
        /// </summary>
        /// <param name="roomID"></param>
        /// <param name="roomName"></param>
        /// <param name="addCondition"></param>
        /// <param name="notice"></param>
        /// <param name="remark"></param>
        public void UpdateRoomBaseInfo(UInt32 roomID, string roomName, byte addCondition, string notice, string remark)
        {
            if (roomID == 0) return;
            if (roomName == null || roomName == string.Empty) return;
            if (addCondition > 2) addCondition = 0;
            var room = new RoomBaseInfo()
            { RoomID = roomID, RoomName = roomName, AddCondition = addCondition, Notice = notice, Remark = remark };
            sendMsg(CommandType.SetRoomBaseInfo, room, roomID, true);
        } 
        #endregion
         
        #region 删除群中用户
        /// <summary>
        /// 删除群中用户
        /// </summary>
        /// <param name="roomID"></param>
        /// <param name="userID"></param>
        public void DelRoomUser(UInt32 roomID, UInt32 userID)
        {
            if (roomID == 0 || userID == 0) return;
            RoomUser ru = new RoomUser();
            ru.UserID = userID;
            ru.RoomID = roomID;
            sendMsg(CommandType.DelRoomUser, ru,  roomID,true );
        }
        #endregion

        #region 设置群管理员
        /// <summary>
        /// 设置群管理员
        /// </summary>
        /// <param name="roomID"></param>
        /// <param name="userID"></param>
        /// <param name="admin"></param>
        public void SetRoomManger(UInt32 roomID, UInt32 userID, bool admin)
        {
            if (roomID == 0 || userID == 0) return;
            RoomUser ru = new RoomUser();
            ru.UserID = userID;
            ru.Admin = admin;
            ru.RoomID = roomID;
            sendMsg(CommandType.SetRoomManger, ru, roomID, true);
        }
        #endregion

        #region 设置群用户名片
        /// <summary>
        /// 设置群用户名片
        /// </summary>
        /// <param name="roomID"></param>
        /// <param name="userID"></param>
        /// <param name="userCard"></param>
        public void SetRoomUserCard(UInt32 roomID, UInt32 userID, string userCard)
        {
            if (roomID == 0 || userID == 0) return;
            RoomUser ru = new RoomUser();
            ru.UserID = userID;
            ru.UserCard = userCard;
            ru.RoomID = roomID;
            sendMsg(CommandType.SetRoomUserCard, ru, roomID, true);
        }
        #endregion

        #endregion

        #region 查找用户或群
        /// <summary>
        /// 查找用户或群
        /// </summary>
        /// <param name="q">查询对像</param>
        public void Query(Query q)
        {
            if (q.QueryClass == QueryClass.None) return;
            sendMsg(CommandType.Query,q);
        }
        #endregion

        #region 用户分组信息操作

        #region 添加用户分组信息
        /// <summary>
        /// 添加用户分组信息
        /// </summary> 
        /// <param name="GroupName"></param>
        /// <returns></returns>
        public void AddUserGroupInfo(string GroupName)
        {
            GroupInfoOperation g = new GroupInfoOperation();
            g.cmd = GroupInfoOperationCmd.Add;
            g.GroupName = GroupName;
            sendMsg(CommandType.UserGroupInfoOperation, g);
        }
        #endregion

        #region 更新用户分组信息
        /// <summary>
        /// 更新用户分组信息
        /// </summary> 
        /// <param name="GroupName"></param>
        /// <param name="NewGroupName"></param>
        /// <returns></returns>
        public void UpdateUserGroupInfo(string GroupName, string NewGroupName)
        {
            GroupInfoOperation g = new GroupInfoOperation();
            g.cmd = GroupInfoOperationCmd.Update;
            g.GroupName = GroupName;
            g.NewGroupName = NewGroupName;
            sendMsg(CommandType.UserGroupInfoOperation, g);
        }
        #endregion

        #region 删除用户分组信息
        /// <summary>
        /// 删除用户分组信息
        /// </summary> 
        /// <param name="GroupName"></param>
        /// <returns></returns>
        public void DelUserGroupInfo(string GroupName)
        {
            GroupInfoOperation g = new GroupInfoOperation();
            g.cmd = GroupInfoOperationCmd.Del;
            g.GroupName = GroupName;
            sendMsg(CommandType.UserGroupInfoOperation, g);
        }
        #endregion

        #endregion

        #region 用户群分组信息操作

        #region 添加群用户分组信息
        /// <summary>
        /// 添加群用户分组信息
        /// </summary> 
        /// <param name="GroupName"></param>
        /// <returns></returns>
        public void AddRoomGroupInfo(string GroupName)
        {
            GroupInfoOperation g = new GroupInfoOperation();
            g.cmd = GroupInfoOperationCmd.Add;
            g.GroupName = GroupName;
            sendMsg(CommandType.RoomGroupInfoOperation, g);
        }
        #endregion

        #region 更新用户群分组信息
        /// <summary>
        /// 更新用户群分组信息
        /// </summary> 
        /// <param name="GroupName"></param>
        /// <param name="NewGroupName"></param>
        /// <returns></returns>
        public void UpdateRoomGroupInfo(string GroupName, string NewGroupName)
        {
            GroupInfoOperation g = new GroupInfoOperation();
            g.cmd = GroupInfoOperationCmd.Update;
            g.GroupName = GroupName;
            g.NewGroupName = NewGroupName;
            sendMsg(CommandType.RoomGroupInfoOperation, g);
        }
        #endregion

        #region 删除用户群分组信息
        /// <summary>
        /// 删除用户群分组信息
        /// </summary> 
        /// <param name="GroupName"></param>
        /// <returns></returns>
        public void DelRoomGroupInfo(string GroupName)
        {
            GroupInfoOperation g = new GroupInfoOperation();
            g.cmd = GroupInfoOperationCmd.Del;
            g.GroupName = GroupName;
            sendMsg(CommandType.RoomGroupInfoOperation, g);
        }
        #endregion

        #endregion

        #region 回应添加好友添加群
        /// <summary>
        /// 回应添加好友邀请
        /// </summary>
        /// <param name="Agree">是否同意</param>
        /// <param name="RequestUserID">请求人帐号</param>
        /// <param name="Reason">拒绝理由</param>
        /// <param name="RemarkName">备注名</param>
        /// <param name="GroupID">分组ID</param>
        public void ResponsesAddFriend(bool Agree, UInt32 RequestUserID, string Reason, string RemarkName="", int GroupID = -1)
        {
            InviteMsg msg = new InviteMsg();
            if (Agree)
                msg.Result = InviteResult.Yes;
            else
                msg.Result = InviteResult.No;
            msg.AttachMsg = Reason;
            msg.RemarkName = RemarkName;
            msg.GroupID = GroupID;
            sendMsg(CommandType.ResponsesAddFriend, msg, RequestUserID, false);
        }


        /// <summary>
        /// 回应添加群邀请
        /// </summary>
        /// <param name="Agree">是否同意</param>
        /// <param name="RoomID">群帐号</param>
        /// <param name="RequestUserID">请求人帐号</param>
        /// <param name="Reason">拒绝理由</param>
        /// <param name="RemarkName">备注名</param>
        /// <param name="GroupID">分组ID</param>
        public void ResponsesAddRoom(bool Agree, UInt32 RoomID, UInt32 RequestUserID, string Reason)
        {
            InviteMsg msg = new InviteMsg();
            msg.UserID = RequestUserID;
            msg.RoomID = RoomID;
            if (Agree)
                msg.Result = InviteResult.Yes;
            else
                msg.Result = InviteResult.No;
            msg.AttachMsg = Reason;
            sendMsg(CommandType.ResponsesAddRoom, msg, RoomID, true);
        }

        /// <summary>
        /// 回应邀请加入群
        /// </summary>
        /// <param name="Agree">是否同意</param>
        /// <param name="RoomID">群帐号</param>
        /// <param name="InviteUserID">邀请人帐号</param>
        /// <param name="Reason">拒绝理由</param>
        /// <param name="RemarkName">备注名</param>
        /// <param name="GroupID">分组ID</param>
        public void ResponsesInviteAddRoom(bool Agree, UInt32 RoomID, UInt32 InviteUserID, string Reason, string RemarkName="", int GroupID = -1)
        {
            InviteMsg msg = new InviteMsg();
            if (Agree)
                msg.Result = InviteResult.Yes;
            else
                msg.Result = InviteResult.No;
            msg.AttachMsg = Reason;
            msg.RoomID = RoomID;

            //sendMsg(CommandType.ResponsesInviteAddRoom, msg, InviteUserID, RoomID);
        }
        #endregion

        #region 添加好友添加群

        #region 添加好友
        /// <summary>
        /// 添加好友
        /// </summary>
        /// <param name="FriendID">好友帐号</param>
        /// <param name="RemarkUserName">备注姓名</param>
        /// <param name="GroupID">分组名</param>
        /// <param name="AttachMsg">附加消息</param>
        public void RequestAddFriend(UInt32 FriendID, string RemarkUserName = "", int GroupID = 1, string AttachMsg = "")
        {
            InviteMsg msg = new InviteMsg();
            msg.AttachMsg = AttachMsg;
            msg.GroupID = GroupID;
            msg.RemarkName = RemarkUserName; 
            sendMsg(CommandType.RequestAddFriend, msg, FriendID, false );
        }
        #endregion

        #region 删除好友
        /// <summary>
        /// 删除好友
        /// </summary>
        /// <param name="FriendID"></param>
        public void DelFriend(UInt32 FriendID)
        {
            sendMsg(CommandType.DelFriend, null, FriendID, false);
        }
        #endregion

        #region 邀请添加群
        /// <summary>
        /// 邀请添加群
        /// </summary>
        /// <param name="roomID">群号</param>
        /// <param name="roomName">备注群名</param>
        /// <param name="usersID">被邀请的用户帐号，多个用户用逗号分开</param>
        public void InviteAddRoom(UInt32 roomID,string usersID)
        {
            InviteMsg msg = new InviteMsg();
            msg.AttachMsg = usersID;
            sendMsg(CommandType.InviteAddRoom, XML.ConvertToArray(msg), roomID, true); 
        }
        #endregion

        #region 请求添加群
        /// <summary>
        /// 请求添加群
        /// </summary>
        /// <param name="roomID">群号</param>
        /// <param name="RemarkRoomName">备注群名</param>
        /// <param name="GroupID">群分组</param>
        /// <param name="AttachMsg">附加消息</param>
        public void RequestAddRoom(UInt32 roomID, string RemarkRoomName = "", int GroupID = -1, string AttachMsg = "")
        {
            InviteMsg msg = new InviteMsg();
            msg.AttachMsg = AttachMsg;
            msg.GroupID = GroupID;
            msg.RemarkName = RemarkRoomName;
            msg.RoomID = roomID;
            sendMsg(CommandType.RequestAddRoom, XML.ConvertToArray(msg), roomID, true);
        }
        #endregion

        #region 退出群
        /// <summary>
        /// 退出群
        /// </summary>
        /// <param name="roomID"></param>
        public void QuitRoom(UInt32 roomID)
        {
            sendMsg(CommandType.QuitRoom, null, roomID, true);
        }
        #endregion

        #region 删除群
        /// <summary>
        /// 删除群
        /// </summary>
        /// <param name="roomID"></param>
        public void DelRoom(UInt32 roomID)
        {
           sendMsg(CommandType.DelRoom , null, roomID, true);
        }
        #endregion

        #endregion

        #region 发送消息

        #region 通用发送消息方法
        /// <summary>
        /// 发送消息到服务器
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="Msg"></param>
        private void sendMsg(CommandType cmd, byte[] Msg)
        {
            sendMsg(cmd, Msg, 0, false);
        }

        /// <summary>
        /// 发送消息给用户或群
        /// </summary>
        /// <param name="cmd">协议指令</param>
        /// <param name="data">消息字符串</param>
        /// <param name="to">消息接收者、群帐号【0为服务器】</param>
        /// <param name="roomID"></param>
        private void sendMsg(CommandType cmd, byte[] payload, UInt32 to, bool ToRoom )
        {
            var msg = new BinaryMsg();
            msg.CommandType = (byte)cmd;
            msg.Compress = false;
            msg.Encrypt = false;
            msg.ToRoom = ToRoom;
            msg.To = to; 
            msg.From = MyAuth.UserID;
            msg.Payload = payload;

            #region 先压缩，后加密
            if ( Compress)
            {
                if (msg.PayloadLength > 1000)
                {
                    var buffer = IMLibrary.GZip.Stream.Compress(msg.Payload);
                    if (buffer.Length < msg.PayloadLength)
                    {
                        msg.Payload = buffer;
                        msg.Compress = true;
                    }
                }
            }

            if (Encrypt)
            {
                if (msg.CommandType == (byte)CommandType.Auth)
                    msg.Payload = Encryption.Encrypt3DES(msg.Payload);
                else
                    msg.Payload = Encryption.Encrypt3DES(msg.Payload, PasswordKey);
                msg.Encrypt = true;
            }
            #endregion 

            wsClient.SendAsync(msg.ToArray(),null );
        }


        /// <summary>
        /// 发送消息到服务器
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="obj"></param>
        private void sendMsg(CommandType cmd, object obj)
        {
            sendMsg(cmd, obj, 0, false);
        }

        /// <summary>
        /// 发送消息给用户或群
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="obj"></param>
        /// <param name="to">消息接收者、群帐号【0为服务器】</param>
        private void sendMsg(CommandType cmd, object obj, UInt32 to, bool ToRoom)
        {
            sendMsg(cmd, XML.ConvertToArray(obj), to, ToRoom);
        }
        #endregion

        #region 发送消息给用户
        /// <summary>
        /// 发送消息给用户
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="UserID"></param>
        public void SendMessageToUser(object msg, UInt32 UserID)
        {
            sendMsg(CommandType.UserMessage, XML.ConvertToArray(msg), UserID, false);
        }
        #endregion

        #region 发送消息给群
        /// <summary>
        /// 发送消息给群
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="RoomID"></param>
        public void SendMessageToRoom(object msg, UInt32 roomID)
        {
            sendMsg(CommandType.RoomMessage, msg, roomID, true);
        }
        #endregion

        #endregion

        #region  释放资源
        public void Disonnect()
        {
            if (wsClient != null)
            {
                wsClient.OnClose -= WsClient_OnClose;
                wsClient.OnOpen -= WsClient_OnOpen;
                wsClient.OnMessage -= WsClient_OnMessage;
                wsClient = null;
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            if (wsClient != null)
            {
                wsClient.Close();
                wsClient.OnClose -= WsClient_OnClose;
                wsClient.OnOpen -= WsClient_OnOpen;
                wsClient.OnMessage -= WsClient_OnMessage;
                wsClient = null;
            }
        }
        #endregion

    }

    #region 客户端消息事件参数
    /// <summary>
    /// 客户端消息事件参数
    /// </summary>
    public class MsgClientEventArgs : System.EventArgs
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="to"></param>
        /// <param name="from"></param>
        public MsgClientEventArgs(object obj, UInt32 to = 0, UInt32 from = 0)
        {
            Obj = obj;
            From = from;
            To = to; 
        }
      
 
        /// <summary>
        /// 参数对像
        /// </summary>
        public object Obj=null;
        /// <summary>
        /// 消息接收者
        /// </summary>
        public UInt32 To;
        /// <summary>
        /// 消息发送者
        /// </summary>
        public UInt32 From; 
    }
    #endregion
}
